package me.flyray.bsin.gateway.portal;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PolicyConditions;
import com.aliyun.oss.model.PutObjectRequest;

import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import lombok.extern.log4j.Log4j2;
import me.flyray.bsin.constants.ResponseCode;
import me.flyray.bsin.enums.CustomerType;
import me.flyray.bsin.enums.TenantAppType;
import me.flyray.bsin.exception.BusinessException;
import me.flyray.bsin.gateway.common.ApiResult;
import me.flyray.bsin.gateway.config.AliOSSProperties;
import me.flyray.bsin.gateway.config.MessageProperties;
import me.flyray.bsin.gateway.context.BaseContextHandler;
import me.flyray.bsin.gateway.service.ExcelService;
import me.flyray.bsin.gateway.utils.GeneratorUtil;
import me.flyray.bsin.oss.ipfs.BsinIpfsService;
import me.flyray.bsin.utils.BsinServiceInvokeUtil;


@Log4j2
@Controller
public class BsinFilePortal implements InitializingBean {

    @Autowired
    private AliOSSProperties aliOSSProperties;
    @Autowired
    private MessageProperties config;
    @Autowired
    private ExcelService excelService;
    @Autowired
    public BsinServiceInvokeUtil bsinServiceInvoke;
    @Autowired
    private BsinIpfsService bsinIpfsService;

    @PostMapping("/upload")
    @ResponseBody
    public ApiResult upload(@RequestParam(value = "file", required = false) MultipartFile file) {
        if (file.isEmpty()) {
            throw new BusinessException(ResponseCode.UPLOAD_PICTURE_NOT_EMPTY);
        }
        // 获取文件名
        String fileName = file.getOriginalFilename();
        //System.out.println("上传的文件名为：" + fileName);
        // 获取文件的后缀名
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        //System.out.println("上传的后缀名为：" + suffixName);
        // 文件上传后的路径
        String filePath = config.getUpPath();
        String newUUID = UUID.randomUUID().toString().replaceAll("-", "");
        String newFileName = newUUID + suffixName;
        //System.out.println(filePath);
        File dest = new File(filePath + newFileName);
        //System.out.println(newFileName);
        // 检测是否存在目录
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        String url = config.getPreImgUrl() + newFileName;
        Map<String, Object> resMap = new HashMap<String, Object>();
        try {
            file.transferTo(dest);
            resMap.put("oldFileName", fileName);
            resMap.put("url", url);
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ApiResult.ok(resMap);
    }

    private String host;

    @Override
    public void afterPropertiesSet() throws Exception {
        host = "http://" + aliOSSProperties.getBucket() + "." + aliOSSProperties.getEndpoint();
    }

    /**
     * 前台签名直传， 由服务器签名，用户可直接上传图片
     * 这种只支持 Aliyun(因为我编码查看文档时，只有阿里云做了这个设计) 优点是 上传不需要占用应用服务器带宽。 目前前端是使用的这个。
     * 若需要更改，请自行修改前端上传逻辑
     *
     * @param request
     * @param response
     */
    @RequestMapping(path = "bsinUpload", method = RequestMethod.GET)
    @ResponseBody
    public ApiResult upload(HttpServletRequest request, HttpServletResponse response) {

        OSSClient ossClient = new OSSClient(aliOSSProperties.getEndpoint(), aliOSSProperties.getAccessKeyId(), aliOSSProperties.getAccessKeySecret());
        JSONObject respJsonObj = new JSONObject();
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, aliOSSProperties.getDir());
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);
            respJsonObj.put("accessid", aliOSSProperties.getAccessKeyId());
            respJsonObj.put("policy", encodedPolicy);
            respJsonObj.put("signature", postSignature);
            respJsonObj.put("dir", aliOSSProperties.getDir());
            respJsonObj.put("host", host);
            respJsonObj.put("expire", String.valueOf(expireEndTime / 1000));
            JSONObject jasonCallback = new JSONObject();
            jasonCallback.put("callbackBody",
                    "filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}");
            jasonCallback.put("callbackBodyType", "application/x-www-form-urlencoded");
            String base64CallbackBody = BinaryUtil.toBase64String(jasonCallback.toString().getBytes());
            respJsonObj.put("callback", base64CallbackBody);
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "GET, POST");
            respJsonObj.put("code", 200);
            respJsonObj.put("fileUrl", aliOSSProperties.getBaseUrl());
        } catch (Exception e) {

        }
        return ApiResult.ok(respJsonObj);
    }

    /**
     * 后台通过服务器间接传文件
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/aliUpload")
    @ResponseBody
    public Object create(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
        OSSClient ossClient = new OSSClient(aliOSSProperties.getEndpoint(), aliOSSProperties.getAccessKeyId(), aliOSSProperties.getAccessKeySecret());
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentLength(file.getSize());
        objectMetadata.setContentType(file.getContentType());
        String ext = FilenameUtils.getExtension(file.getOriginalFilename());
        String uuid = GeneratorUtil.genFileName();
        PutObjectRequest putObjectRequest = new PutObjectRequest(aliOSSProperties.getBucket(), aliOSSProperties.getDir() + uuid + "." + ext, file.getInputStream(), objectMetadata);
        ossClient.putObject(putObjectRequest);
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("fileUrl", aliOSSProperties.getBaseUrl() + aliOSSProperties.getDir() + uuid + "." + ext);
        return ApiResult.ok(data);
    }

    /**
     * 批量导入
     */
    @PostMapping("/importExcel")
    @ResponseBody
    public Object importExcel(@RequestParam(value = "file") MultipartFile file) {

        try {
            List cpqRiskAreaList = excelService.importExcel(file);
            Map<String, Object> data = new HashMap<String, Object>();
            data.put("cpqRiskAreaList", cpqRiskAreaList);
            bsinServiceInvoke.genericInvoke("AdminRiskAreaService", "batchAdd", "1.0", data);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ApiResult.ok();
    }

    /**
     * 批量导入
     */
    @GetMapping("/downloadExcel")
    @ResponseBody
    public Object downloadExcel(HttpServletResponse response) {
        String inFileName = "template.xlsx";
        String fileName = "sort.xlsx";
        excelService.downloadExcel(response, inFileName, fileName);
        return ApiResult.ok();
    }

    /**
     * 上传文件到ipfs
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/ipfsUploadTest")
    @ResponseBody
    public Object ipfsUploadTest(@RequestParam("file") MultipartFile file) throws IOException {
        String filename = file.getOriginalFilename();
        if (filename == null) {
            return new HashMap<>();
        }
        String customerNo = (String) BaseContextHandler.get("customerNo");
        String currentPath = "/leonard";
        JSONObject result = bsinIpfsService.ipfsAdd(file.getBytes(), filename);

        try {
            bsinIpfsService.ipfdCP(result.get("Hash").toString(), currentPath, filename);
        } catch (Exception e) {
            System.out.println("ipfdCP error...." + e.toString());
        }

        return ApiResult.ok(result);
    }

    /**
     * 上传文件到ipfs和服务器
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/adminIpfsUpload")
    @ResponseBody
    public Object adminIpfsUpload(@RequestParam("file") MultipartFile file, @RequestParam("currentPath") String currentPath,
            @RequestParam("tenantAppType") String tenantAppType, HttpServletRequest request) throws IOException {
        if (file.isEmpty()) {
            throw new BusinessException(ResponseCode.UPLOAD_PICTURE_NOT_EMPTY);
        }
        String token = request.getHeader("Authorization");
        JWT jwt = null;
        jwt = JWTUtil.parseToken(token);
        String tenantId = (String) jwt.getPayload("tenantId");

        String fileName = file.getOriginalFilename();
        if (fileName == null) {
            return new HashMap<>();
        }

        // 根据用户类型判断用户属于哪个平台
        String dev = "bigan";
        if (TenantAppType.BSIN_JIUJIU.getCode().equals(tenantAppType)) {
            dev = "jiujiu";
        } else if (TenantAppType.BSIN_DAOBOOK.getCode().equals(tenantAppType)) {
            dev = "daobook";
        }
        String localPath = config.getUpPath() + dev + "/" + tenantId + currentPath + "/";
        currentPath = "/" + dev + "/" + tenantId + currentPath;
        JSONObject result = null;
        byte[] fileByte = null;
        // 上传文件到服务器
        try {
            log.debug("currentPath: " + currentPath);
            log.debug("localPath: " + localPath);
            Path path = Paths.get(localPath);
            Path pathCreate = Files.createDirectories(path);

            System.out.println("上传的文件名为：" + fileName);
            // 获取文件的后缀名
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            System.out.println("上传的后缀名为：" + suffixName);
            //System.out.println(filePath);
            File dest = new File(localPath + fileName);
            // 检测是否存在目录
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
                String url = config.getPreImgUrl() + fileName;
            Map<String, Object> resMap = new HashMap<String, Object>();
            fileByte = file.getBytes();
            try {
                file.transferTo(dest);
                resMap.put("oldFileName", fileName);
                resMap.put("url", url);
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            System.out.println("存储本地服务器 error...." + e.toString());
            return ApiResult.fail(e.toString());
        }
        // 上传文件到ipfs----会有 java.lang.RuntimeException: ipfsadmin.s11edao.com 异常，忽略
        result = bsinIpfsService.ipfsAdd(fileByte, fileName);
        try {
            //检查当前文件夹是否存在-不存在则创建
            String hashDir = bsinIpfsService.fileStat(currentPath).get("Hash").toString();
            log.info("fileStat: ",hashDir);
            // 移植到一个目录文件夹
            bsinIpfsService.ipfdCP(result.get("Hash").toString(), currentPath, fileName);
        } catch (Exception e) {
            //TODO 目录移植失败不影响使用，目录下文件存在则会抛出异常
            System.out.println("ipfdCP error...." + e.toString());
        }
        return ApiResult.ok(result);
    }


    /**
     * 上传文件到ipfs
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/ipfsUpload")
    @ResponseBody
    public Object ipfsUpload(@RequestParam("file") MultipartFile file, @RequestParam("currentPath") String currentPath, HttpServletRequest request) throws IOException {
        String token = request.getHeader("Authorization");
        JWT jwt = null;
        jwt = JWTUtil.parseToken(token);
        String tenantId = (String) jwt.getPayload("tenantId");

        String filename = file.getOriginalFilename();
        if (filename == null) {
            return new HashMap<>();
        }
        String customerType = (String) BaseContextHandler.get("customerType");
        // 根据用户类型判断用户属于哪个平台
        String dev = "bigan";
        if (CustomerType.TENANT.getCode().equals(customerType)) {
            dev = "daobook";
        }
        currentPath = "/" + dev + "/" + tenantId + currentPath;
        // 上传文件到ipfs
        JSONObject result = bsinIpfsService.ipfsAdd(file.getBytes(), filename);
        try {
            // 移植到一个目录文件夹
            bsinIpfsService.ipfdCP(result.get("Hash").toString(), currentPath, filename);
        } catch (Exception e) {
            System.out.println("ipfdCP error...." + e.toString());
        }
        return ApiResult.ok(result);
    }

    /**
     * 上传文件到ipfs
     *
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping("/ipfsUpload-test")
    @ResponseBody
    public Object ipfsUpload(@RequestParam("file") MultipartFile file, @RequestParam String customerNo, @RequestParam String currentPath, @RequestParam(defaultValue = "bigan") String dev) throws IOException {
        String filename = file.getOriginalFilename();
        if (filename == null) {
            return new HashMap<>();
        }
        JSONObject result = bsinIpfsService.ipfsAdd(file.getBytes(), filename);
        currentPath = "/" + dev + "/" + customerNo + "/" + currentPath;
        try {
            bsinIpfsService.ipfdCP(result.get("Hash").toString(), currentPath, filename);
        } catch (Exception e) {
            System.out.println("ipfdCP error...." + e.toString());
        }

        return ApiResult.ok(result);
    }


    @GetMapping("/ipfsLsTest")
    @ResponseBody
    public Object ipfsFileStatTest(@RequestParam("currentPath") String currentPath) throws IOException {
        currentPath = "/" + currentPath;

        String hashDir = bsinIpfsService.fileStat(currentPath).get("Hash").toString();
        JSONObject result = bsinIpfsService.fileLS(hashDir);
        return ApiResult.ok(result);
    }

}
